package com.touchstone.cloudpacs.common.utils;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.validation.FieldError;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by 梁亮 on 2015/9/8 0008.
 * Cell:15884457479
 * Email:dreamto1@126.com
 * Description:
 * <p/>
 * Functions:
 * 1.
 */
public class CommonUtils {
    static SimpleDateFormat ymdhms = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    static SimpleDateFormat ymdhm = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    static SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd");
    static SimpleDateFormat ym = new SimpleDateFormat("yyyy-MM");
    static Random random = new Random();

    private static final char[] codes = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
    };
    private static final char[] letters = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };

    /**
     * 手机号校验正则表达式
     */
    public static final String REGEXP_PHONE = "^[1][3,4,5,7,8][0-9]{9}$";
    /**
     * 身份证号校验正则表达式
     */
    public static final String REGEXP_ID_CARD = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
            "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
    /**
     * 邮箱校验正则表达式
     */
    public static final String REGEXP_EMAIL = "^([a-z0-9A-Z]+[-|\\.|_]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";

    /**
     * 判断对象为空
     *
     * @param obj
     * @return
     */
    public static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;

        } else if (obj instanceof String && (obj.toString().trim().equals(""))) {
            return true;

        } else if (obj instanceof Number && ((Number) obj).doubleValue() == 0) {
            return true;

        } else if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
            return true;

        } else if (obj instanceof Map && ((Map) obj).isEmpty()) {
            return true;

        } else if (obj instanceof Object[] && ((Object[]) obj).length == 0) {
            return true;

        } else {
            return false;
        }
    }

    /**
     * 判断对象不为空
     *
     * @param obj
     * @return
     */
    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }

    /**
     * 生成唯一ID
     *
     * @return
     */
    public static String getUuid() {
        UUID uuid = UUID.randomUUID();
        //去掉横杆
//        uuid.toString().replace("-", "")
        return uuid.toString();
    }

    /**
     * 判断是否是邮箱
     *
     * @param email
     * @return true:是  false:否
     */
    public static boolean isEmail(String email) {
        if (isEmpty(email)) {
            return false;
        }
        boolean tag = true;
        final Pattern pattern = Pattern.compile(REGEXP_EMAIL);
        final Matcher mat = pattern.matcher(email);
        if (!mat.find()) {
            tag = false;
        }
        return tag;
    }

    public static boolean isPassword(String password) {
        if (isEmpty(password)) {
            return false;
        }
        return password.length() >= 6;
    }

    public static boolean isMobilePhone(String phone) {
        int phoneLength = 11;
        if (phone.length() != phoneLength) {
            return false;
        }
        return rexExpCheck(REGEXP_PHONE, phone);
    }

    public static boolean isIDCard(String idCard) {
        int minLength = 15, maxLength = 18;
        if (idCard.length() != minLength && idCard.length() != maxLength) {
            return false;
        }
        return rexExpCheck(REGEXP_ID_CARD, idCard);
    }

    private static boolean rexExpCheck(String pattern, String text) {
        Pattern idCardPattern = Pattern.compile(pattern);
        Matcher m = idCardPattern.matcher(text);
        boolean isMatch = m.matches();
        if (!isMatch) {
            return false;
        }
        return true;
    }


    /**
     * 组装字符串
     *
     * @param ss    字符串列表
     * @param split 分割符
     * @return 组合过后字符串
     */
    public static String combination(String[] ss, String split) {
        if (ss.length == 0)
            return null;
        StringBuffer sb = new StringBuffer();
        for (String str : ss) {
            sb.append(str);
            sb.append(split);
        }
        return sb.toString().substring(0, sb.length() - 1);
    }

    /**
     * 修正页码
     *
     * @param value
     * @return
     */
    public static Integer checkPage(Object value) {
        Integer page = 0;
        if (value != null) {
            if (value instanceof String) {
                page = Integer.parseInt((String) value);
            } else if (value instanceof Integer) {
                page = (Integer) value;
            }
            page = page < 0 ? 0 : page;
        }
        return page;
    }

    /**
     * 获取请求IP地址
     *
     * @param request
     * @return
     */
    public static String getIP(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 功能描述: 返回浏览器类型
     *
     * @param request
     * @return
     * @author hunter
     * @date 2019-4-24 024 上午 10:58:46
     */
    public static String getBrowser(HttpServletRequest request) {
        String agent = request.getHeader("User-Agent").toLowerCase();
        if (agent.indexOf("msie 7") > 0) {
            return "ie7";
        } else if (agent.indexOf("msie 8") > 0) {
            return "ie8";
        } else if (agent.indexOf("msie 9") > 0) {
            return "ie9";
        } else if (agent.indexOf("msie 10") > 0) {
            return "ie10";
        } else if (agent.indexOf("msie") > 0) {
            return "ie";
        } else if (agent.indexOf("opera") > 0) {
            return "opera";
        } else if (agent.indexOf("firefox") > 0) {
            return "firefox";
        } else if (agent.indexOf("webkit") > 0) {
            return "webkit";
        } else if (agent.indexOf("gecko") > 0 && agent.indexOf("rv:11") > 0) {
            return "ie11";
        } else {
            return "Others";
        }
    }

    /**
     * 比较时间大小 返回date1是否大于date2
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean before(Date date1, Date date2) {
        return date1.getTime() > date2.getTime();
    }

    /**
     * 返回自定义时间格式
     *
     * @param format 时间格式
     * @param date   时间
     * @return 自定义的字符串
     */
    public static String getCustomDateFormat(String format, Date date) {
        SimpleDateFormat dateFormat;
        try {
            dateFormat = new SimpleDateFormat(format);
            return dateFormat.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 日期格式化成:"yyyy-MM-dd HH:mm:ss"
     *
     * @param date
     * @return
     */
    public static String getymdhms(Date date) {
        return ymdhms.format(date);
    }

    /**
     * 日期格式化成:"yyyy-MM-dd HH:mm"
     *
     * @param date
     * @return
     */
    public static String getymdhm(Date date) {
        return ymdhm.format(date);
    }

    /**
     * 日期格式化成:"yyyy-MM-dd"
     *
     * @param date
     * @return
     */
    public static String getymd(Date date) {
        return ymd.format(date);
    }

    /**
     * 日期格式化成:"yyyy-MM"
     *
     * @param date
     * @return
     */
    public static String getym(Date date) {
        return ym.format(date);
    }

    /**
     * 返回日期年份 (参数为空返回当前年份)
     *
     * @param date
     * @return
     */
    public static Integer getYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        if (isNotEmpty(date)) {
            calendar.setTime(date);
        }
        return calendar.get(Calendar.YEAR);
    }

    public static Date getDateBySecond(String dateStr) {
        if (isEmpty(dateStr)) {
            return null;
        }
        Date date = null;
        try {
            date = ymdhms.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 获取时间偏移的有效链接时间
     *
     * @return
     */
    public static Date getValidityTime(int day, int hour, int minute) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, day);
        calendar.add(Calendar.HOUR_OF_DAY, hour);
        calendar.add(Calendar.MINUTE, minute);
        return calendar.getTime();
    }

    public static String getRandomCode(int code_num) {
        char[] arr = ArrayUtils.addAll(codes, letters);
        return getRandomStr(code_num, arr);
    }

    public static String getRandomMixedCode(int code_num) {
        String result = getRandomCode(code_num);
        int numberCounter = 0, letterCounter = 0;
        for (int i = 0, length = result.length(); i < length; i++) {
            if (ArrayUtils.contains(codes, result.charAt(i))) {
                numberCounter++;
            }
            if (ArrayUtils.contains(letters, result.charAt(i))) {
                letterCounter++;
            }
        }
        if (numberCounter == code_num || letterCounter == code_num) {
            result = getRandomMixedCode(code_num);
        }
        return result;
    }

    public static String getRandomNumberStr(int code_num) {
        return getRandomStr(code_num, codes);
    }

    public static String getRandomLetters(int code_num) {
        return getRandomStr(code_num, letters);
    }

    private static String getRandomStr(int code_num, char[] sources) {
        StringBuilder builder = new StringBuilder("");
        for (int i = 0; i < code_num; i++) {
            builder.append(sources[random.nextInt(sources.length - 1)]);
        }
        return String.valueOf(builder);
    }

    public static <T> List<T> listToList(List list, Class<T> entityClass) {
        List<T> data = new ArrayList<T>();
        if (null != list && null != entityClass) {
            for (Object ad : list) {
                data.add(CommonUtils.objectToEntity(ad, entityClass));
            }
        }
        return data;
    }

    public static <T> T objectToEntity(Object object, Class<T> entityClass) {
        T result = null;
        if (object != null && entityClass != null) {
            try {
                result = (T) Class.forName(entityClass.getName()).newInstance();
                Field[] fields = object.getClass().getDeclaredFields();
                List<String> fieldList = getFieldNameList(entityClass);
                Field resultField = null;
                for (Field field : fields) {
                    field.setAccessible(true);
                    if (fieldList.contains(field.getName()) && field.get(object) != null) {
                        resultField = entityClass.getDeclaredField(field.getName());
                        resultField.setAccessible(true);
                        if (resultField.getType().equals(Integer.class) || resultField.getType().equals(int.class)) {
                            resultField.set(result, Integer.valueOf(String.valueOf(field.get(object))));
                        } else if (resultField.getType().equals(Date.class)) {
                            if (field.getType().equals(Date.class)) {
                                resultField.set(result, field.get(object));
                            } else if (field.getType().equals(String.class)) {
                                resultField.set(result, CommonUtils.getDateBySecond(String.valueOf(field.get(object))));
                            }
                        } else if (resultField.getType().equals(String.class)) {
                            if (field.getType().equals(Date.class)) {
                                resultField.set(result, getymdhm((Date) field.get(object)));
                            } else {
                                resultField.set(result, String.valueOf(field.get(object)));
                            }
                        }
                    }
                }
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public static void objectToObject(Object object, Object objectTo) {
        if (object != null && objectTo != null) {
            try {
                Field[] fields = object.getClass().getDeclaredFields();
                List<String> fieldList = getFieldNameList(objectTo.getClass());
                Field resultField = null;
                for (Field field : fields) {
                    field.setAccessible(true);
                    if (fieldList.contains(field.getName()) && field.get(object) != null) {
                        resultField = objectTo.getClass().getDeclaredField(field.getName());
                        resultField.setAccessible(true);
                        if (resultField.getType().equals(Integer.class) || resultField.getType().equals(int.class)) {
                            resultField.set(objectTo, Integer.valueOf(String.valueOf(field.get(object))));
                        } else if (resultField.getType().equals(Date.class)) {
                            if (field.getType().equals(Date.class)) {
                                resultField.set(objectTo, field.get(object));
                            } else if (field.getType().equals(String.class)) {
                                resultField.set(objectTo, CommonUtils.getDateBySecond(String.valueOf(field.get(object))));
                            }
                        } else {
                            resultField.set(objectTo, String.valueOf(field.get(object)));
                        }

                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static List<String> getFieldNameList(Class cla) {
        if (isEmpty(cla)) {
            return null;
        }
        List<String> result = new ArrayList<String>();
        for (Field field : cla.getDeclaredFields()) {
            result.add(field.getName());
        }
        return result;
    }

    public static String getErrors(List<FieldError> fieldErrorList) {
        StringBuffer sb = new StringBuffer();
        for (FieldError fieldError : fieldErrorList) {
            sb.append(fieldError.getField());
            sb.append(":");
            sb.append(fieldError.getDefaultMessage());
            sb.append(";");
        }
        return sb.toString();
    }

    public static Object[] findAnnotation(Method method, Class annotationClass) {
        Object methodAnnotation = method.getAnnotation(annotationClass);
        Object classAnnotation = method.getDeclaringClass().getAnnotation(annotationClass);
        Object[] result = {classAnnotation, methodAnnotation};
        return result;
    }

    public static String getNumber(String str) {
        if (str == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        Pattern p = Pattern.compile("(\\d+)");
        Matcher m = p.matcher(str);
        while (m.find()) {
            sb.append(m.group(1));
        }
        return sb.toString();
    }

    public static Map<String, Object> object2Map(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    public static String polishing2(Integer param) {
        if (isEmpty(param)) {
            return "00";
        } else if (param.compareTo(10) < 0) {
            return "0" + param;
        } else {
            return param + "";
        }
    }

    public static char[] randomString(int seed) {
        Random random = new Random(5);
        return String.valueOf(random.nextInt()).toCharArray();
    }

    /**
     * 根据出生年月日计算当前的年龄
     * <p/>
     * 默认出生0岁，默认日期一到就长一岁
     *
     * @param birthdayTimeMillis 出生年月日的毫秒值
     * @return 目前日期为止的年龄
     */
    public static int getAge(long birthdayTimeMillis) {
        //当前日历对象
        Calendar now = Calendar.getInstance();
        //出生年月日日历对象
        Calendar birth = Calendar.getInstance();
        birth.setTimeInMillis(birthdayTimeMillis);

        if (birth.after(now)) {
            return 0;
        }

        int nowYear = now.get(Calendar.YEAR);
        int nowMonth = now.get(Calendar.MONTH);
        int nowDay = now.get(Calendar.DAY_OF_MONTH);

        int birthYear = birth.get(Calendar.YEAR);
        int birthMonth = birth.get(Calendar.MONTH);
        int birthDay = birth.get(Calendar.DAY_OF_MONTH);

        //默认 当前月份已经过了生日的月份
        int age = nowYear - birthYear;
        //如果月份没过，则计算的年龄可能要减1
        //计算的年龄需要减1的情况有：如果月份还没到，年龄直接减1，都不用看日期；或者如果月份相等，但日期还没到，年龄减1
        boolean isBefore = (nowMonth < birthMonth) || (nowMonth == birthMonth && nowDay < birthDay);
        if (isBefore) {
            age--;
        }
        return age;
    }

    public static int getAge(Date date) {
        return getAge(date.getTime());
    }
}
